package io.yichen.usbflutter.usb.driver;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.util.Log;

import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;

import java.io.IOException;

import io.yichen.usbflutter.usb.UsbPermission;

public class UsbConnector {

    public static final String INTENT_ACTION_GRANT_USB = "io.yichen.usbflutter.GRANT_USB";
    private static final String TAG = "UsbConnector";

    private UsbPermission usbPermission = UsbPermission.Unknown;

    private UsbSerialPort usbSerialPort;
    private boolean connected;
    private SerialInputOutputManager usbIoManager;

    public UsbResult connect(Context context, UsbItem item, int baudRate, SerialInputOutputManager.Listener listener) {
        UsbDevice device = null;
        UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        for (UsbDevice v : usbManager.getDeviceList().values())
            if (v.getDeviceId() == item.device.getDeviceId())
                device = v;
        if (device == null) {
            Log.d(TAG, "connection failed: device not found");
            return UsbResult.err().msg("没有找到设备");
        }
        UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
        if (driver == null) {
            driver = CustomProber.getCustomProber().probeDevice(device);
        }
        if (driver == null) {
            Log.d(TAG, "connection failed: no driver for device");
            return UsbResult.err().msg("没有可用的驱动");
        }
        int portNum = item.port;
        if (driver.getPorts().size() < portNum) {
            Log.d(TAG, "connection failed: not enough ports at device");
            return UsbResult.err().msg("设备端口不可用");
        }
        usbSerialPort = driver.getPorts().get(portNum);
        UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
        if (usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
            usbPermission = UsbPermission.Requested;
            int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
            PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(context, 0,
                    new Intent(INTENT_ACTION_GRANT_USB), flags);
            usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
            return UsbResult.err().msg("连接失败请开启权限后再试");
        }
        if (usbConnection == null) {
            if (!usbManager.hasPermission(driver.getDevice())) {
                Log.d(TAG, "connection failed: permission denied");
                return UsbResult.err().msg("连接失败:请开启权限");
            }
            Log.d(TAG, "connection failed: open failed");
            return UsbResult.err().msg("连接失败");
        }

        try {
            usbSerialPort.open(usbConnection);
            try {
                usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
            } catch (UnsupportedOperationException e) {
                Log.d(TAG, "unsupport setparameters");
            }

            usbIoManager = new SerialInputOutputManager(usbSerialPort, listener);
            usbIoManager.start();
            Log.d(TAG, "connected");
            connected = true;
            return UsbResult.suc().msg("连接成功");
        } catch (Exception e) {
            Log.d(TAG, "connection failed: " + e.getMessage());
            disconnect();
            return UsbResult.err().msg("连接失败，发生异常");
        }
    }

    public void disconnect() {
        connected = false;
        if (usbIoManager != null) {
            usbIoManager.setListener(null);
            usbIoManager.stop();
        }
        usbIoManager = null;
        try {
            usbSerialPort.close();
        } catch (IOException ignored) {
        }
        usbSerialPort = null;
    }

}
